package sy4_Creational_Pattern.builder.wuzeng2;

import lombok.Data;

@Data
class Product {   //角色1：复杂产品类 Product，表示被建造的对象
	private String food;
	private String drink;
}

abstract class Builder  { //角色2：抽象建造者
	//产品部件构建
	public abstract void buildFood();
	public abstract void buildDrink();
	//完整产品构建
	public abstract Product buildProduct();

	public boolean isNeedDrink(){   //钩子方法
		return true;  //套餐默认包含饮料
	}
}

class KFCBuilder extends Builder  { //角色3：具体建造者类；KFC：肯德基
	//部件名称
	private String food;
	private String drink;

	public KFCBuilder() {  //构造方法
		System.out.println("肯德基快餐");
	}

	@Override
	public void buildFood() {  //重写基类方法
		this.food="炸鸡";
	}

	@Override
	public void buildDrink() {  //重写基类方法
		this.drink="百事可乐";
	}

	@Override
	public Product buildProduct() { //重写基类方法
		Product product = new Product();
		product.setFood(food);

		//调用钩子方法
		if(isNeedDrink()) {  //参与产品构建
		//if(!isNeedDrink()) {  //不参与产品构建
			product.setDrink(drink);
		}

		return product;  
	}
}

class McDonaldBuilder extends Builder  { //角色3：具体建造者类；McDonald's：麦当劳
	//部件名称
	private String food;
	private String drink;

	public McDonaldBuilder() {  //构造方法
		System.out.println("麦当劳快餐");
	}

	@Override
	public void buildFood() {  //重写基类方法
		this.food="汉堡";
	}

	@Override
	public void buildDrink() {  //重写基类方法
		this.drink="可口可乐";
	}

	@Override
	public Product buildProduct() { //重写基类方法
		Product product = new Product();
		product.setFood(food);
		product.setDrink(drink);
		return product;
	}
}

class Director  { //角色4：指挥者类Director，聚合Builder对象，指挥产品的建造过程
	private Builder builder;  //聚合

	public Director(Builder builder) {  //构造器注入
		this.builder = builder;
	}

	public Product construct() {  //构建（装配）方法
		//调用建造者，可以使用钩子方法控制产品的建造
		builder.buildFood();
		builder.buildDrink();
		return builder.buildProduct();  //返回复杂产品
	}
}

public class Client { //客户端
	public static void main(String[] args) {
		//使用指挥者，客户端程序就不需要知道产品建造细节；相同的建造过程，有不同的产品表示
		Director director=new Director(new KFCBuilder());
		//Director director=new Director(new McDonaldBuilder());
		Product product = director.construct();
		System.out.println(product);
		
		//如果不使用指挥者，客户端程序则需要知道产品建造细节
		Builder builder = new McDonaldBuilder();
		//注释下面两行构建代码，将输出空产品
		builder.buildFood();
		builder.buildDrink();
		System.out.println(builder.buildProduct());
	}
}
